﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;

namespace UpdateV3
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Task.Run(ReadCurrentVersion);
        }


        // HttpWebRequest is old
        // Gitee api: searching release in the doc
        // https://gitee.com/api/v5/swagger#/getV5ReposOwnerRepoReleases
        private const string AllReleasesUrl = "https://gitee.com/api/v5/repos/transgithub/update-v3/releases";
        private const string LatestReleaseUrl = "https://gitee.com/api/v5/repos/transgithub/update-v3/releases/latest";
        private static readonly HttpClient RestClient = new();

        private string? _newFileDownloadLink;

        private async Task CheckLatestVersion()
        {
            try
            {
                var request = new HttpRequestMessage(HttpMethod.Get, LatestReleaseUrl);
                var response = await RestClient.SendAsync(request);
                var latestRelease = await response.Content.ReadFromJsonAsync<ReleaseObject>();

                if (latestRelease is null)
                {
                    throw new Exception("Can not get update info");
                }

                _newFileDownloadLink = latestRelease.assets.First().browser_download_url;
                Dispatcher.Invoke(() =>
                {
                    LatestVersion.Content = latestRelease.tag_name;
                    if (latestRelease.tag_name == CurrentVersion.Content.ToString())
                    {
                        LatestVersion.Foreground = Brushes.Green;
                    }
                    else
                    {
                        LatestVersion.Foreground = Brushes.Red;
                        FoundNewVersionGroupBox.Visibility = Visibility.Visible;
                        var name = latestRelease.name;
                        var body = latestRelease.body;
                        UpdateInfoTextBlock.Text = name + "\n\n" + body;
                    }
                });
            }
            catch (HttpRequestException e)
            {
                MessageBox.Show("\nException Caught!\nMessage :{0} ", e.Message);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }

        private void ReadCurrentVersion()
        {
            var filename = "update-log.txt";
            if (!File.Exists(filename))
            {
                File.WriteAllText(filename, "0.0.0");
            }
            var version = File.ReadLines(filename).First();
            Dispatcher.Invoke(() => CurrentVersion.Content = version);

            Task.Run(async () => await CheckLatestVersion());
        }

        private readonly string _zipFilePath = Path.Combine(Directory.GetCurrentDirectory(), "tmp");
        private readonly WebClient _webClient = new();

        private void UpdateButtonOnClick(object sender, RoutedEventArgs e)
        {
            UpdateButton.IsEnabled = false;
            DownloadProgressBar.Visibility = Visibility.Visible;
            _webClient.DownloadProgressChanged += (s, e) => DownloadProgressBar.Value = e.ProgressPercentage;
            _webClient.DownloadFileCompleted += (s, e) => UnzipFile();
            _webClient.DownloadFileAsync(new Uri(_newFileDownloadLink), _zipFilePath);
        }

        private void UnzipFile()
        {
            var extractPath = Directory.GetCurrentDirectory();
            ZipArchiveHelper.ExtractToDirectory(_zipFilePath, extractPath, true);
            Dispatcher.Invoke(() =>
            {
                CurrentVersion.Content = LatestVersion.Content;
                LatestVersion.Foreground = Brushes.Green;
            });
            try
            {
                File.Delete(_zipFilePath);
            }
            catch (IOException e)
            {
                MessageBox.Show(e.Message);
                return;
            }
        }

    }

    // from https://stackoverflow.com/questions/14795197/forcefully-replacing-existing-files-during-extracting-file-using-system-io-compr
    public static class ZipArchiveHelper
    {
        public static void ExtractToDirectory(string archiveFileName, string destinationDirectoryName, bool overwrite)
        {
            if (!overwrite)
            {
                ZipFile.ExtractToDirectory(archiveFileName, destinationDirectoryName);
            }
            else
            {
                using var archive = ZipFile.OpenRead(archiveFileName);

                foreach (var file in archive.Entries)
                {
                    var completeFileName = Path.Combine(destinationDirectoryName, file.FullName);
                    var directory = Path.GetDirectoryName(completeFileName);

                    if (!Directory.Exists(directory) && !string.IsNullOrEmpty(directory))
                        Directory.CreateDirectory(directory);

                    if (file.Name != "")
                        file.ExtractToFile(completeFileName, true);
                }
            }
        }
    }
}